(import
  ;; unit tests
  (srfi srfi-64)
  ;; module to test
  (list-utils))


(test-begin "list-utils-test")

(test-group
 "list-prefixq-test"

 (test-assert "list-prefixq-00"
   (list-prefix? '(a b c) '(a b)))

 (test-assert "list-prefixq-01"
   (list-prefix? '(a b c) '(a b c)))

 (test-assert "list-prefixq-02"
   (not (list-prefix? '(a b c) '(a b c d))))

 (test-assert "list-prefixq-03"
   (list-prefix? '(a b c) '(a)))

 (test-assert "list-prefixq-04"
   (not (list-prefix? '(a b c) '(b))))

 (test-assert "list-prefixq-05"
   (list-prefix? '(a b c) '()))

 (test-assert "list-prefixq-06"
   (list-prefix? '() '())))

(test-group
 "make-multiple-recursive-list-remover"

 (test-equal "make-multiple-recursive-list-remover-00"
   '(a b (c) (d))
   ((make-multiple-recursive-list-remover equal?)
    '(a b (c) (d (e f))) '(e f)))

 (test-equal "make-multiple-recursive-list-remover-01"
   '(a b (c) (d (e f)))
   ((make-multiple-recursive-list-remover equal?)
    '(a b (c) (e f) (d (e (e f) f))) '(e f)))

 ;; Define both bindings to have the same value, but they
 ;; are different objects, so eq? should be #f.
 (let ([num1 10]
       [num2 10])
   (test-equal "make-multiple-recursive-list-remover-02"
     ;; The number must not be removed.
     `(a b (c) (d (,num1)))
     ((make-multiple-recursive-list-remover eq?)
      ;; Put different bindings in the lists.
      `(a b (c) (d (,num1))) `(,num2))))

 ;; Define both bindings to have the same value, but they
 ;; are different objects, so eq? should be #f.
 (let ([num1 10]
       [num2 10])
   (test-equal "make-multiple-recursive-list-remover-03"
     ;; The number must not be removed, because eqv? does
     ;; not deal with lists.
     `(a b (c) (d (,num1)))
     ((make-multiple-recursive-list-remover eqv?)
      ;; Put different bindings in the lists.
      `(a b (c) (d (,num1))) `(,num2))))

 ;; Define both bindings to have the same value, but they
 ;; are different objects, so eq? should be #f.
 (test-equal "make-multiple-recursive-list-remover-04"
   ;; The number must be removed. eqv? can deal with
   ;; numbers.
   '(a b (c) (d))
   ((make-multiple-recursive-list-remover eqv?)
    ;; Put different bindings in the lists.
    '(a b (c) (d 10)) 10))

 ;; Define both bindings to have the same value, but they
 ;; are different objects, so eq? should be #f.
 (let ([num1 10]
       [num2 10])
   (test-equal "make-multiple-recursive-list-remover-05"
     ;; The number must be removed.
     `(a b (c) (d))
     ((make-multiple-recursive-list-remover equal?)
      ;; Put different bindings in the lists.
      `(a b (c) (d (,num1))) `(,num2)))))

(test-group
 "make-multiple-list-remover"

 (test-equal "make-multiple-list-remover-00"
   ;; cannot remove in sublist
   '(a b (c) (d (e f)))
   ((make-multiple-list-remover equal?)
    '(a b (c) (d (e f))) '(e f)))

 (test-equal "make-multiple-list-remover-01"
   ;; can remove in top level
   '(a b (c) (d))
   ((make-multiple-list-remover equal?)
    '(a b (c) (d) (e f)) '(e f)))

 (test-equal "make-multiple-list-remover-02"
   ;; can remove in top level, but remains in sublist
   '(a b (c) (d (e f)))
   ((make-multiple-list-remover equal?)
    '(a b (c) (d (e f)) (e f)) '(e f)))


 ;; Define both bindings to have the same value, but they
 ;; are different objects, so eq? should be #f.
 (let ([a '(9 10)]
       ;; We must specify b not as literal, but a list created using the list
       ;; constructor, because Guile puts equal? lists defined in the same top
       ;; level expression into the same place in the store, which makes them
       ;; actually eq?.
       [b (list 9 10)])
   (test-equal "make-multiple-list-remover-03"
     `(1 2 (3) (4) ,a)
     ((make-multiple-list-remover eq?)
      `(1 2 (3) (4) ,a) b)))

 ;; Define both bindings to have the same value, but they
 ;; are different objects, so eq? should be #f.
 (let ([num1 10]
       [num2 10])
   (test-equal "make-multiple-list-remover-04"
     ((make-multiple-recursive-list-remover eqv?)
      ;; Put different bindings in the lists.
      `(a b (c) (d (,num1))) `(,num2))
     ;; The number must not be removed, because eqv? does
     ;; not deal with lists.
     `(a b (c) (d (,num1)))))

 (test-equal "make-multiple-list-remover-05"
   ;; removes on top level, but not in sub list
   '(a b (c) (d 10))
   ((make-multiple-list-remover eqv?)
    '(a b (c) (d 10)) 10))

 (let ([num1 10] [num2 10])
   (test-equal "make-multiple-list-remover-06"
     ((make-multiple-list-remover equal?)
      ;; Put different bindings in the lists.
      `(a b (c) (d (,num1))) `(,num2))
     ;; The number must be removed.
     `(a b (c) (d (,num1))))))


(test-group
 "map-to-all-except-last-test"

 (test-equal "applies procedure to all but the last element -- 00"
   '(2 3 4 4)
   (map-to-all-except-last
    (λ (elem)
      (+ elem 1))
    '(1 2 3 4))))


(test-end "list-utils-test")
